﻿//Ajax类，需要proto.js模块

if (!window.wkh.classes) {
    window.wkh.classes = {};
}

wkh.classes.Ajax = (function () {//ajax库
    function encodeData(data) {//编码对象属性
        if (!data) return "";
        var pairs = [];
        for (var name in data) {
            if (!data.hasOwnProperty(name)) continue;//跳过继承属性
            if (typeof data[name] === "function") continue;//跳过方法

            var value = data[name];
            name = encodeURIComponent(name).replace("%20", "+");
            if (Array.isArray(value)) {//如果value为数组，折分
                var length = value.length;
                for (var i = 0; i < length; ++i) {
                    pairs.push(name + "=" + encodeURIComponent(value[i].toString()).replace("%20", "+"));
                }
            } else {
                value = encodeURIComponent(value.toString()).replace("%20", "+");
                pairs.push(name + "=" + value);
            }
        }

        return pairs.join("&");
    }

    function getFormData(data) {//得到multipart/form-data对象
        if (!data) return "";
        var formData = new FormData();
        for (var name in data) {
            if (!data.hasOwnProperty(name)) continue;//跳过继承属性
            if (typeof data[name] === "function") continue;//跳过方法

            var value = data[name];
            if (Array.isArray(value)) {
                var length = value.length;
                for (var i = 0; i < length; ++i) {
                    formData.append(name, value[i]);
                }
            } else {
                formData.append(name, value);
            }
        }

        return formData;
    }

    function encodeText(data) {//得到text/plain对象
        if (!data) return "";
        var pairs = [];
        for (var name in data) {
            if (!data.hasOwnProperty(name)) continue;//跳过继承属性
            if (typeof data[name] === "function") continue;//跳过方法

            var value = data[name];
            name = name.replace(" ", "+");
            if (Array.isArray(value)) {//如果value为数组，折分
                var length = value.length;
                for (var i = 0; i < length; ++i) {
                    pairs.push(name + "=" + value[i].toString().replace(" ", "+"));
                }
            } else {
                value = value.toString().replace(" ", "+");
                pairs.push(name + "=" + value);
            }
        }

        return pairs.join("&");
    }

    function setHeader(xhr, headerObj) {//设置信息头
        if (!headerObj) return;

        for (var name in headerObj) {
            if (!headerObj.hasOwnProperty(name)) continue;//跳过继承属性
            if (typeof headerObj[name] === "function") continue;//跳过方法

            var value = headerObj[name];
            if (Array.isArray(value)) {//如果value为数组，折分
                var length = value.length;
                for (var i = 0; i < length; ++i) {
                    xhr.setRequestHeader(name, value[i]);
                }
            } else {
                xhr.setRequestHeader(name, value);
            }
        }

        return;
    }

    var pri;//私有变量公有化

    var wlS = window.localStorage;

    var modified = {
        name: [],
        value:[]
    };//保存last-modifed头
    var etag = {
        name:[],
        value:[]
    };//保存etag

    if (wlS.__wkh_private_modifiedName!=null&&wlS.__wkh_private_modifiedValue!=null) {
        var names = wlS.__wkh_private_modifiedName.split(" ");
        var values = wlS.__wkh_private_modifiedValue.split(" ");
        if (names.length === values.length) {
            modified.name = names;
            modified.value = values;
        } else {
            wlS.__wkh_private_modifiedName = wlS.__wkh_private_modifiedValue = "";
        }
    } else {
        wlS.__wkh_private_modifiedName = wlS.__wkh_private_modifiedValue = "";
    }

    if (wlS.__wkh_private_etagName!=null && wlS.__wkh_private_etagValue!=null) {
        var names = wlS.__wkh_private_etagName.split(" ");
        var values = wlS.__wkh_private_etagValue.split(" ");
        if (names.length === values.length) {
            etag.name = names;
            etag.value = values;
        } else {
            etag.__wkh_private_etagName = etag.__wkh_private_etagValue = "";
        }
    } else {
        etag.__wkh_private_etagName = etag.__wkh_private_etagValue = "";
    }

    

    var globeSetting = {
        method: "POST",
        async: true,

        modifyCheck: false,
        etagCheck: false,
        cache:false,

        contentType: "application/x-www-form-urlencoded",
        encode: true,
        timeout: 0
    };

    

    function classAjax(url, setting) {
        var privateVar = {
            request: new XMLHttpRequest(),
            method: (setting.method||globeSetting.method).toUpperCase(),//发送方法
            url: url,//发送地址
            async: setting.async === false ? false : globeSetting.async,//是否异步

            modifyCheck: setting.modifyCheck||globeSetting.modifyCheck,
            etagCheck: setting.etagCheck||globeSetting.etagCheck,
            cache:setting.cache||globeSetting.cache,

            userName: setting.userName,//用户名
            passWord: setting.passWord,//密码
            contentType: setting.contentType || globeSetting.contentType,//编码
            data: setting.data || globeSetting.data,//发送的数据
            encode: setting.encode === false ? false : globeSetting.encode,//是否对发送的数据进行编码
            header: setting.header,//请求头
            timeout: setting.timeout || globeSetting.timeout,//超时时间
            overrideType: setting.overrideType||globeSetting.overrideType,//覆盖mime类型
            dataFilter: setting.dataFilter||globeSetting.dataFilter,//数据预处理器,若为自定义readyStateChange，该方法无效，需要在自定义的事件中自行处理

            //事件
            event: {
                readyStateChange: [],//状态改变
                beforesend: [],//发送前
                complete: [],//完成
                success: [],//成功
                timeout: [],//超时
                error: [],//错误
                abort: []//打断后执行程序
            },

            //进度事件
            progressEvent: {
                onloadstart: [],
                onprogress: [],
                onload: [],
                onerror: [],
                ontimeout: [],
                onloadend: [],
                onabort: []
            },

            //下载进度事件
            uploadEvent: {
                uploadloadstart: [],
                uploadprogress: [],
                uploadload: [],
                uploaderror: [],
                uploadtimeout: [],
                uploadloadend: [],
                uploadabort: []
            }
        };

        this.__wkh_private_getAjaxPrivate = function () {
            pri = privateVar;
        };

        if (privateVar.encode) {//对数据进行编码
            switch (privateVar.contentType) {
                case "application/x-www-form-urlencoded":
                    privateVar.data = encodeData(privateVar.data); break;
                case "multipart/form-data":
                    privateVar.data = getFormData(privateVar.data); privateVar.method = "POST"; break;
                case "text/plain":
                    privateVar.data = encodeText(privateVar.data); break;
                default:
                    privateVar.data = encodeData(privateVar.data); break;
            }
        }

        if (privateVar.method === "GET") {
            privateVar.url = privateVar.url + "?" + privateVar.data;
        }

        var request = privateVar.request;

        request.onreadystatechange = function () {
            //函数体

            function doEvent(e, type) {
                var length = privateVar.event[type].length;
                for (var i = 0; i < length; ++i) {
                    privateVar.event[type][i].call(request, e);
                }
            }

            doEvent({ xhr: request }, "readyStateChange");//执行readyStateChange事件

            if (request.readyState === 4) {//如果完成请求
                doEvent({ xhr: request, status: request.status, statusText: request.statusText }, "complete");//执行完成事件

                if (request.status === 200 || request.status === 304) {//如果为连接正常,或文件未改变

                    if (request.status === 304) {
                        console.log("http返回状态码：304");
                    }//debug

                    if (privateVar.modifyCheck) {
                        var lastModified = request.getResponseHeader("Last-Modified");
                        if (!lastModified) {
                            lastModified = "0";
                        }

                        var i = -1;
                        if ((i = modified.name.contains(privateVar.url)) !== -1) {
                            modified.value[i] = lastModified;
                        } else {
                            modified.name.push(privateVar.url);
                            modified.value.push(lastModified);
                        }

                        wlS.__wkh_private_modifiedName = modified.name.join(" ");
                        wlS.__wkh_private_modifiedValue = modified.value.join(" ");

                        console.log(lastModified);//debug
                    }

                    if (privateVar.etagCheck) {
                        var etagStr = request.getResponseHeader("Etag");
                        if (!etagStr) {
                            etagStr = "0";
                        }

                        var i = -1;
                        if ((i = etag.name.contains(privateVar.url)) !== -1) {
                            etag.value[i] = etagStr;
                        } else {
                            etag.name.push(privateVar.url);
                            etag.value.push(etagStr);
                        }

                        wlS.__wkh_private_etagName = etag.name.join(" ");
                        wlS.__wkh_private_etagValue = etag.value.join(" ");

                        console.log(etagStr);//debug
                    }

                    var contentType;
                    if (privateVar.overrideType) {
                        contentType = privateVar.overrideType.toLowerCase();
                    } else {
                        contentType = request.getResponseHeader("Content-Type");
                        if (!contentType) {
                            contentType = "txt";
                        } else{
                            contentType = contentType.toLowerCase();
                        }
                    }

                    var json, xml, txt;

                    var type;
                    var isJsonError = false;
                    var isJsonNull = false;
                    if (contentType.indexOf("xml") !== -1 || contentType.indexOf("html") !== -1) {//若为xml或html文档
                        type = "xml";
                        if (request.responseXML!== undefined) {//如果存在responseXML属性
                            xml = request.responseXML;
                            if (xml !== null) {
                                xml.type = "document";
                            }
                        } else {//否则用一个documentFragment对象包裹节点数据
                            var div = document.createElement("div");
                            div.innerHTML = request.responseText;

                            xml = document.createDocumentFragment();
                            while (div.firstChild) {
                                xml.appendChild(div.firstChild);
                            }
                            xml.type = "documentFragment";
                        }
                        if (privateVar.dataFilter) {//数据预处理
                            xml = privateVar.dataFilter(xml);
                        }
                    } else if (contentType === "application/json" || contentType.indexOf("json") !== -1) {//如果为json数据
                        type = "json";
                        if (!request.responseText) {//如果responseText无反回值，则json为null
                            isJsonNull = true;
                            json = null;
                        } else {
                            try {
                                json = JSON.parse(request.responseText);
                                if (privateVar.dataFilter) {//数据预处理
                                    json = privateVar.dataFilter(json);
                                }
                            } catch (e) {//json解析错误
                                isJsonError = true;
                            }
                        }
                    } else {//否则为文本数据
                        type = "txt";
                        txt = request.responseText;
                        if (privateVar.dataFilter) {//数据预处理
                            txt = privateVar.dataFilter(txt);
                        }
                    }

                    if (isJsonError) {//json解析错误
                        doEvent({ xhr: request, status: 101, statusText: "JSON parse error" }, "error");
                    } else if (isJsonNull) {
                        doEvent({ xhr: request, status: 0, statusText: "JSON is Null" }, "error");
                    } else {//否则执行success事件
                        doEvent({ xhr: request, status: request.status, statusText: request.statusText, type: type, contentType: contentType, json: json, xml: xml, txt: txt }, "success");
                    }
                } else {//执行error事件
                    doEvent({ xhr: request, status: request.status, statusText: request.statusText }, "error");
                }
            }
        };

        request.open(privateVar.method, privateVar.url, privateVar.async, privateVar.userName, privateVar.passWord);//打开连接
        request.setRequestHeader("content-type", privateVar.contentType);//设置编码方式

        var ifModifiedSince = -1;
        if (privateVar.modifyCheck && (ifModifiedSince = modified.name.contains(privateVar.url))!==-1) {
            request.setRequestHeader("If-Modified-Since", modified.value[ifModifiedSince]);

            console.log("url:" + modified.name[ifModifiedSince] + "\nLast-Modified:" + modified.value[ifModifiedSince]);//debug
        }

        var ifNoneMatch = -1;
        if(privateVar.etagCheck&&(ifNoneMatch=etag.name.contains(privateVar.url))!==-1){
            request.setRequestHeader("If-None-Match", modified.value[ifNoneMatch]);

            console.log("url:" + etag.name[ifNoneMatch] + "\nEtag:" + etag.value[ifNoneMatch]);//debug
        }

        if (privateVar.cache) {
            request.setRequestHeader("Cache-Control", privateVar.cache);
        }

        if (request.timeout !== undefined && privateVar.timeout !== 0) {//如果存在timeout属性，且类中timeout不为0
            request.timeout = privateVar.timeout;
        }

        if (request.overrideMimeType && privateVar.overrideType !== undefined) {
            request.overrideMimeType(privateVar.overrideType);
        }

        setHeader(request, privateVar.header);//设置头

        //设置进度事件
        var length, i;
        if (request.onloadstart) {
            request.onloadstart = function () {
                length = privateVar.progressEvent.onloadstart.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.onloadstart[i].apply(request, arguments);
                }
            };
        }
        if (request.onprogress) {
            request.onprogress = function () {
                length = privateVar.progressEvent.onprogress.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.onprogress[i].apply(request, arguments);
                }
            };
        }
        if (request.onload) {
            request.onload = function () {
                length = privateVar.progressEvent.onload.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.onload[i].apply(request, arguments);
                }
            };
        }
        if (request.onerror) {
            request.onerror = function () {
                length = privateVar.progressEvent.onerror.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.onerror[i].apply(request, arguments);
                }
            };
        }
        if (request.ontimeout) {
            request.ontimeout = function () {
                length = privateVar.event.timeout.length;
                for (i = 0; i < length; ++i) {
                    privateVar.event.timeout[i].call(request, { xhr: pri.request, status: "102", statusText: "timeout" });
                }
                length = privateVar.progressEvent.ontimeout.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.ontimeout[i].apply(request, arguments);
                }
            };
        }
        if (request.onloadend) {
            request.onloadend = function () {
                length = privateVar.progressEvent.onloadend.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.onloadend[i].apply(request, arguments);
                }
            };
        }
        if (request.onabort) {
            request.onabort = function () {
                length = privateVar.progressEvent.onabort.length;
                for (i = 0; i < length; ++i) {
                    privateVar.progressEvent.onabort[i].apply(request, arguments);
                }
            };
        }

        //设置下载进度事件
        if (request.upload) {
            if (request.upload.onloadstart) {
                request.upload.onloadstart = function () {
                    length = privateVar.uploadEvent.uploadloadstart.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploadloadstart[i].apply(request, arguments);
                    }
                };
            }
            if (request.upload.onprogress) {
                request.upload.onprogress = function () {
                    length = privateVar.uploadEvent.uploadprogress.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploadprogress[i].apply(request, arguments);
                    }
                };
            }
            if (request.upload.onload) {
                request.upload.onload = function () {
                    length = privateVar.uploadEvent.uploadload.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploadload[i].apply(request, arguments);
                    }
                };
            }
            if (request.upload.onerror) {
                request.upload.onerror = function () {
                    length = privateVar.uploadEvent.uploaderror.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploaderror[i].apply(request, arguments);
                    }
                };
            }
            if (request.upload.ontimeout) {
                request.upload.ontimeout = function () {
                    length = privateVar.uploadEvent.uploadtimeout.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploadtimeout[i].apply(request, arguments);
                    }
                };
            }
            if (request.upload.onloadend) {
                request.upload.onloadend = function () {
                    length = privateVar.uploadEvent.uploadloadend.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploadloadend[i].apply(request, arguments);
                    }
                };
            }
            if (request.upload.onabort) {
                request.upload.onabort = function () {
                    length = privateVar.uploadEvent.uploadabort.length;
                    for (i = 0; i < length; ++i) {
                        privateVar.uploadEvent.uploadabort[i].apply(request, arguments);
                    }
                };
            }
        }
    }

    classAjax.prototype.addEventListener = function (eventType, fn) {//添加事件侦听器
        this.__wkh_private_getAjaxPrivate();

        var fnArr;
        if (eventType.match(/^on/)) {
            fnArr = pri.progressEvent[eventType];
        } else if (eventType.match(/^upload/)) {
            fnArr = pri.uploadEvent[eventType];
        } else {
            fnArr = pri.event[eventType];
        }

        if (Array.isArray(fnArr)) {
            if (fnArr.contains(fn)===-1) {
                fnArr.push(fn);
            }
        }

        return this;
    };

    classAjax.prototype.removeEventListener = function (eventType, fn) {//移除事件侦听器
        this.__wkh_private_getAjaxPrivate();

        var fnArr;
        if (eventType.match(/^on/)) {
            fnArr = pri.progressEvent[eventType];
        } else if (eventType.match(/^upload/)) {
            fnArr = pri.uploadEvent[eventType];
        } else {
            fnArr = pri.event[eventType];
        }

        if (Array.isArray(fnArr)) {
            var i;
            var length;
            if (i = fnArr.contains(fn)) {
                length = fnArr.length;
                for (; i < length - 1; ++i) {
                    fnArr[i] = fnArr[i + 1];
                }
                fnArr.length = length - 1;
            }
        }

        return this;
    };

    classAjax.prototype.send = function () {
        this.__wkh_private_getAjaxPrivate();

        var returnValue = null;
        var isSend = true;

        var length = pri.event.beforesend.length;
        for (var i = 0; i < length; ++i) {//执行beforeSend事件函数，传递request参数
            returnValue = pri.event.beforesend[i].call(pri.request, { xhr: pri.request });
            if (returnValue === false) {
                isSend = false;
            }
        }

        if (isSend) {//成功发送
            if (pri.method === "GET") {
                pri.request.send();
            } else {
                pri.request.send(pri.data);
            }

            if (pri.request.timeout === undefined && pri.timeout !== 0) {//如果不存在timeout属性，且类中timeout不为0
                setTimeout(function () {//模拟实现timeout功能
                    var temp = pri.progressEvent.onabort;
                    var temp2 = pri.uploadEvent.uploadabort;
                    pri.progressEvent.onabort = pri.uploadEvent.uploadabort = [];//将abort事件缓存，置空

                    pri.request.abort();//停止

                    pri.progressEvent.onabort = temp;
                    pri.uploadEvent.uploadabort = temp2;//恢复abort事件

                    var length = pri.event.timeout.length;//执行timeout事件
                    for (i = 0; i < length; ++i) {
                        pri.event.timeout[i].call(request, { xhr: pri.request, status: "102", statusText: "timeout" });
                    }
                }, pri.timeout);
            }
            return true;
        } else {//不发送
            return false;
        }
    };

    classAjax.prototype.abort = function () {
        this.__wkh_private_getAjaxPrivate();

        var length = pri.event.abort.length;//执行abort事件
        for (i = 0; i < length; ++i) {
            pri.event.abort[i].call(request, { xhr: pri.request, status: pri.request.status, statusText: pri.request.statusText });
        }

        pri.request.abort();
    };

    classAjax.prototype.className = "Ajax";

    classAjax.setGlobe = function (obj) {//设置Ajax类全局默认参数
        for (var n in obj) {
            globeSetting[n] = obj[n];
        }
    };

    classAjax.clear = function () {
        wlS.removeItem("__wkh_private_modifiedValue");
        wlS.removeItem("__wkh_private_modifiedName");
        wlS.removeItem("__wkh_private_etagName");
        wlS.removeItem("__wkh_private_etagValue");
    };

    classAjax.__wkh_private_className = "Ajax";

    return classAjax;
}());